#include "LuaScript.h"
#include <string>
#include <windows.h>
#include <ComCat.h>
#include <activscp.h>


CComModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_LuaScript, LuaScript)
END_OBJECT_MAP()

void GetScriptEngines()
{
	// get the component category manager for this machine
	ICatInformation *pci = 0;

	HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
		0, CLSCTX_SERVER, IID_ICatInformation, (void**)&pci);
	if (SUCCEEDED(hr))
	{
		// get the list of parseable script engines
		CATID rgcatidImpl[1];
		rgcatidImpl[0] = CATID_ActiveScriptParse;
		IEnumCLSID *pec = 0;

		hr = pci->EnumClassesOfCategories(1, rgcatidImpl, 0, 0, 
			&pec);
		if (SUCCEEDED(hr))
		{
			// print the list of CLSIDs to the console as ProgIDs
			enum {CHUNKSIZE = 16};
			CLSID rgclsid[CHUNKSIZE];
			ULONG cActual;

			do
			{
				hr = pec->Next(CHUNKSIZE, rgclsid, &cActual);
				if (FAILED(hr))
					break;
				if (hr == S_OK)
					cActual = CHUNKSIZE;
				for (ULONG i = 0; i < cActual; i++)
				{
					OLECHAR *pwszProgID = 0;
					if (SUCCEEDED(ProgIDFromCLSID(rgclsid[i], &pwszProgID)))
					{
						std::wstring X = pwszProgID;
						CoTaskMemFree(pwszProgID);
					}
				}
			}
			while (hr != S_FALSE);
			pec->Release();
		}
		pci->Release();
	}
}


LuaScript::LuaScript(void)
{
	m_pass = NULL ;
	L = lua_open();
}

LuaScript::~LuaScript(void)
{
}

STDAPI DllCanUnloadNow(void)
{
    return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
}

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    return _Module.GetClassObject(rclsid, riid, ppv);
}

STDAPI DllRegisterServer(void)
{
    // registers object, typelib and all interfaces in typelib
    HRESULT hr = _Module.DllRegisterServer(FALSE);
	return hr;
}

STDAPI DllUnregisterServer(void)
{
	return _Module.DllUnregisterServer(FALSE);
}

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	//axtam::AXTam::hinstance = hInstance;
	//return _Module.DllMain(hInstance, dwReason, lpReserved, &_Module, CLSID_LuaScript); 
	//return _Module.DllMain(dwReason, lpReserved);
    if (dwReason == DLL_PROCESS_ATTACH)
    {
		_Module.Init(ObjectMap, hInstance, &LIBID_LuaScriptLib);
        DisableThreadLibraryCalls(hInstance);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
        _Module.Term();
    return TRUE; // ok
}

// IActiveScript
STDMETHODIMP LuaScript::SetScriptSite( 
    /* [in] */ IActiveScriptSite *pass)
{
	if (!pass) return E_POINTER;
	m_pass = pass ;
	//TODO stock pass pointer
	return S_OK ;
}


STDMETHODIMP LuaScript::GetScriptSite( 
            /* [in] */ REFIID riid,
            /* [iid_is][out] */ void **ppvObject)
{
	if (!m_pass) {
		return E_FAIL;
	}
	return m_pass->QueryInterface(riid, ppvObject);
}

STDMETHODIMP LuaScript::SetScriptState( 
            /* [in] */ SCRIPTSTATE ss)
{
	return 0;
}

STDMETHODIMP LuaScript::GetScriptState( 
            /* [out] */ SCRIPTSTATE *pssState)
{
	if ( *pssState == SCRIPTSTATE_CONNECTED )
		return S_OK; //TODO: run script
	return S_OK;
}

STDMETHODIMP LuaScript::Close(void)
{
	lua_close(L);
	L = NULL ;
	return S_OK;
}

STDMETHODIMP LuaScript::AddNamedItem( 
            /* [in] */ LPCOLESTR pstrName,
            /* [in] */ DWORD dwFlags)
{
	return S_OK;
}

STDMETHODIMP LuaScript::AddTypeLib( 
            /* [in] */ REFGUID rguidTypeLib,
            /* [in] */ DWORD dwMajor,
            /* [in] */ DWORD dwMinor,
            /* [in] */ DWORD dwFlags)
{
	ATLTRACENOTIMPL(_T("LuaScript::AddTypeLib"));
}

STDMETHODIMP LuaScript::GetScriptDispatch( 
            /* [in] */ LPCOLESTR pstrItemName,
            /* [out] */ IDispatch **ppdisp)
{
	return S_OK;
}

STDMETHODIMP LuaScript::GetCurrentScriptThreadID( 
            /* [out] */ SCRIPTTHREADID *pstidThread)
{
	ATLTRACENOTIMPL(_T("LuaScript::GetCurrentScriptThreadID"));
}

STDMETHODIMP LuaScript::GetScriptThreadID( 
            /* [in] */ DWORD dwWin32ThreadId,
            /* [out] */ SCRIPTTHREADID *pstidThread)
{
	ATLTRACENOTIMPL(_T("LuaScript::GetScriptThreadID"));
}

STDMETHODIMP LuaScript::GetScriptThreadState( 
            /* [in] */ SCRIPTTHREADID stidThread,
            /* [out] */ SCRIPTTHREADSTATE *pstsState)
{
	ATLTRACENOTIMPL(_T("LuaScript::GetScriptThreadState"));
}


STDMETHODIMP LuaScript::InterruptScriptThread( 
            /* [in] */ SCRIPTTHREADID stidThread,
            /* [in] */ const EXCEPINFO *pexcepinfo,
            /* [in] */ DWORD dwFlags)
{
	return S_OK;
}

STDMETHODIMP LuaScript::Clone( 
            /* [out] */ IActiveScript **ppscript)
{
	ATLTRACENOTIMPL(_T("LuaScript::Clone"));
}

STDMETHODIMP LuaScript::ParseScriptText( 
            /* [in] */ LPCOLESTR pstrCode,
            /* [in] */ LPCOLESTR pstrItemName,
            /* [in] */ IUnknown *punkContext,
            /* [in] */ LPCOLESTR pstrDelimiter,
            /* [in] */ DWORD dwSourceContextCookie,
            /* [in] */ ULONG ulStartingLineNumber,
            /* [in] */ DWORD dwFlags,
            /* [out] */ VARIANT *pvarResult,
            /* [out] */ EXCEPINFO *pexcepinfo)
{
	char code[] = ""; //TODO: convert wchart to char
	//load chunk but don't run it
	luaL_loadstring( L, code );
	/*
	return callEngine(NULL, "ParseScriptText",
	                  core->toAtom(pstrCode),
	                  core->toAtom(pstrItemName),
	                  undefinedAtom, // XXX - punkContext,
	                  core->toAtom(pstrDelimiter),
	                  core->toAtom(dwSourceContextCookie),
	                  core->toAtom(ulStartingLineNumber),
	                  core->toAtom(dwFlags),
	                  (Atom)-1);*/
	return S_OK ;
}

STDMETHODIMP LuaScript::InitNew(void)
{
	return S_OK; //TODO
}

STDMETHODIMP LuaScript::AddScriptlet( 
            /* [in] */ LPCOLESTR pstrDefaultName,
            /* [in] */ LPCOLESTR pstrCode,
            /* [in] */ LPCOLESTR pstrItemName,
            /* [in] */ LPCOLESTR pstrSubItemName,
            /* [in] */ LPCOLESTR pstrEventName,
            /* [in] */ LPCOLESTR pstrDelimiter,
            /* [in] */ DWORD dwSourceContextCookie,
            /* [in] */ ULONG ulStartingLineNumber,
            /* [in] */ DWORD dwFlags,
            /* [out] */ BSTR *pbstrName,
            /* [out] */ EXCEPINFO *pexcepinfo)
{
	ATLTRACENOTIMPL(_T("CActiveScript::AddScriptlet"));
}

STDMETHODIMP LuaScript::GetInterfaceSafetyOptions( 
            /* [in] */ REFIID riid,
            /* [out] */ DWORD *pdwSupportedOptions,
            /* [out] */ DWORD *pdwEnabledOptions)
{
	if (!pdwSupportedOptions || !pdwEnabledOptions)
		return E_POINTER;
	*pdwSupportedOptions = (DWORD)-1;//INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACESAFE_FOR_UNTRUSTED_CALLER;
	*pdwEnabledOptions = safetyOptions;
	return S_OK;
}

STDMETHODIMP LuaScript::SetInterfaceSafetyOptions( 
            /* [in] */ REFIID riid,
            /* [in] */ DWORD dwOptionSetMask,
            /* [in] */ DWORD dwEnabledOptions)
{
	safetyOptions &= ~dwOptionSetMask;
	safetyOptions |= dwEnabledOptions;
	return S_OK;
}